import express, { json } from "express";
import path from "path";
import fs from "fs";
import compressing from "compressing"; //zip插件
import formidable from "formidable"; //表单插件
import DB from "../../nedb/index.js";
export { nedb };
import { rootPath, tempPathUpload, tempPathDownload } from "./api.assets.js";

let router = express.Router();
let nedb = new DB("./nedb/db/ax-app.db", [{ fieldName: "name", unique: true }]);

// let filePath = "D:\\my\\vpp\\ax-assets-temp\\upload\\2bdb3473782f5a55fad3fb301.sdk.zip";
// console.warn("[unZip]", filePath);
// let unZipPath = filePath + ".uncompress";
// compressing.zip.uncompress(filePath, unZipPath);

/**
 * 应用配置(json字符串封装应用配置字符串)
 * @param {*} str
 * @returns {String}
 */
function appStr2configCode(str) {
  return `(function (root, obj) {
    if (typeof exports === "object" && typeof module === "object") module.exports = obj;
    else if (typeof define === "function" && define.amd) define([], obj);
    else if (typeof exports === "object") exports["AxeApp"] = obj;
    else return root["AxeApp"] = obj;
  })(typeof self !== "undefined" ? self : this, ${str});`;
}
/**
 * 通过字符串解析应用配置
 * @param {*} str
 * @returns {Object}
 */
function resolveAppOfString(str) {
  try {
    let fn = new Function(`let self={};let define=undefined;let exports=undefined;return ${str};`);
    return str ? fn() : null;
  } catch (error) {
    console.error("[解析应用配置异常11]", error);
  }
}

function dateFormat(time, fmt) {
  var date = new Date(time);
  fmt = fmt || "YYYY-MM-DD HH:mm:ss ";
  var o = {
    "M+": date.getMonth() + 1,
    //月份
    "D+": date.getDate(),
    //日
    "H+": date.getHours(),
    //小时
    "m+": date.getMinutes(),
    //分
    "s+": date.getSeconds(),
    //秒
    "q+": Math.floor((date.getMonth() + 3) / 3),
    //季度
    S: date.getMilliseconds() //毫秒
  };
  if (/(Y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length));

  for (var k in o) {
    if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, RegExp.$1.length == 1 ? o[k] : ("00" + o[k]).substr(("" + o[k]).length));
  }

  return fmt;
}
//下载应用
router.get("/download", async function (req, res, next) {
  var params = req.query;
  // console.log("[下载应用]", params);
  var appConfigPath = path.join(rootPath, params.id, "ax-app/app.config.js");
  if (!fs.existsSync(appConfigPath)) {
    return res.json({ code: -1, message: "没有应用配置文件:" + appConfigPath });
  }
  let appConfig = fs.readFileSync(appConfigPath);
  let app = resolveAppOfString(appConfig);
  // console.log("[下载应用][app]", app, appConfig);
  if (!app || !app.id) {
    return res.json({ code: -1, message: "应用配置不合法:" + appConfigPath, app });
  }
  let dir = tempPathDownload;
  if (!fs.existsSync(dir)) {
    fs.mkdirSync(dir, { recursive: true });
  }
  var appName = app.componentName;
  var zipFileName = `${appName}.zip`;
  var zipFilePath = `${dir}/${appName}.zip`;

  function handleError(error) {
    // console.error("[应用打包异常]", error);
    res.json({ code: -1, message: "应用下载失败", error });
  }

  function handleFinish() {
    // console.log("[应用打包完成]", zipFileName, path.resolve(zipFilePath));
    res.download(zipFilePath, zipFileName, (error) => {
      // console.log("[发送应用结束]");
      error && console.error("[发送应用 error]", error);
      fs.existsSync(zipFilePath) && fs.rmSync(zipFilePath); //下载结束,清楚缓存文件
    });
  }

  var zipStream = fs.createWriteStream(zipFilePath);
  var streamDir = new compressing.zip.Stream();

  // streamDir.addEntry(`./app-static/axe`, { relativePath: "./", ignoreBase: true });

  //  streamDir.addEntry(path.join(rootPath, params.id, "ax-app"), { ignoreBase: false });//不能排除指定目录
  var axAppPath = path.join(rootPath, params.id); //低代码应用私有资源目录
  (fs.existsSync(axAppPath) ? fs.readdirSync(axAppPath) : []).forEach((item, i) => {
    console.log("[低代码应用私有资源目录]", item);
    let exclude = [".cache"].includes(item); //排除指定目录或文件
    !exclude && streamDir.addEntry(`${axAppPath}/${item}`, { relativePath: `./${item}`, ignoreBase: true }); //写入系统资源
  });

  streamDir.addEntry(`./app-static/ax-sys`, { relativePath: "ax-sys", ignoreBase: true });
  streamDir.addEntry(`./app-static/axe.html`, { relativePath: "index.html" });
  // streamDir.addEntry(`./app-static/axe.html`, { relativePath: "axe.html" });
  // streamDir.addEntry(Buffer.from(str), {
  //   relativePath: "assets/app.config.js"
  // });
  streamDir.on("error", handleError).pipe(zipStream).on("error", handleError).on("finish", handleFinish);
});

//下载应用sdk
router.get("/download/sdk", function (req, res, next) {
  var params = req.query;
  // console.log("[下载应用]", params);
  var appConfigPath = path.join(rootPath, params.id, "ax-app/app.config.js");
  if (!fs.existsSync(appConfigPath)) {
    return res.json({ code: -1, message: "没有应用配置文件:" + appConfigPath });
  }
  let appConfig = fs.readFileSync(appConfigPath);
  let app = resolveAppOfString(appConfig);
  // console.log("[下载应用][sdk]", app, appConfig);
  if (!app || !app.id) {
    return res.json({ code: -1, message: "应用配置不合法:" + appConfigPath, app });
  }
  let dir = tempPathDownload;
  if (!fs.existsSync(dir)) {
    fs.mkdirSync(dir, { recursive: true });
  }
  var appName = app.componentName;

  var zipFileName = `${appName}.sdk.zip`;
  var zipFilePath = `${dir}/${zipFileName}`;

  function handleError(error) {
    // console.error("[应用打包异常]", error);
    res.json({ code: -1, message: "应用下载失败", error });
  }

  function handleFinish() {
    // console.log("[应用打包完成]", zipFileName, path.resolve(zipFilePath));
    res.download(zipFilePath, zipFileName, (error) => {
      // console.log("[发送应用结束]");
      error && console.error("[发送应用 error]", error);
      fs.existsSync(zipFilePath) && fs.rmSync(zipFilePath); //下载结束,清楚缓存文件
    });
  }

  var zipStream = fs.createWriteStream(zipFilePath);
  var streamDir = new compressing.zip.Stream();

  streamDir.addEntry(`./app-static/ax-sdk`, { relativePath: "./", ignoreBase: true }); //低代码应用sdk项目模板目录

  var axPath = `./app-static/ax-sys`; //低代码应用系统资源目录
  (fs.existsSync(axPath) ? fs.readdirSync(axPath) : []).forEach((item, i) => {
    console.log("[低代码应用系统资源目录]", item);
    let exclude = ["axed"].includes(item); //排除指定目录或文件
    !exclude && streamDir.addEntry(`./app-static/ax/${item}`, { relativePath: `./public/ax-sys/${item}`, ignoreBase: true }); //写入系统资源
  });

  // streamDir.addEntry(path.join(rootPath, params.id), { relativePath: "./public", ignoreBase: true });//不能排除指定目录
  var axAppPath = path.join(rootPath, params.id); //低代码应用私有资源目录
  (fs.existsSync(axAppPath) ? fs.readdirSync(axAppPath) : []).forEach((item, i) => {
    console.log("[低代码应用私有资源目录]", item);
    let exclude = [".cache"].includes(item); //排除指定目录或文件
    !exclude && streamDir.addEntry(`${axAppPath}/${item}`, { relativePath: `./public/${item}`, ignoreBase: true }); //写入系统资源
  });

  // streamDir.addEntry(Buffer.from(str), {
  //   relativePath: "assets/app.config.js"
  // });
  streamDir.on("error", handleError).pipe(zipStream).on("error", handleError).on("finish", handleFinish);
});

/**
 * @description 修改文件夹内所有文件权限
 * @param {*} directory
 * @param {*} permission
 */
function changePermission(directory, permission = 0o777) {
  let files = fs.readdirSync(directory);
  // let chmodSync = fs.chmodSync(directory, permission);
  // console.log("修改文件夹权限", chmodSync, directory);
  // console.log("\n文件夹文件列表", files, directory);
  for (const i in files) {
    let file = files[i];
    let fullPath = path.join(directory, file);
    if (fs.statSync(fullPath).isDirectory()) {
      changePermission(fullPath, permission);
    } else {
      let chmodSync = fs.chmodSync(fullPath, permission);
      console.log("修改文件权限", chmodSync, fullPath);
    }
  }
}

//上传应用
router.post("/upload", async function (req, res, next) {
  let uploadDir = tempPathUpload;
  !fs.existsSync(uploadDir) && fs.mkdirSync(uploadDir, { recursive: true }); // 判断文件夹是否存在,没用递归创建文件夹
  let form = formidable({
    // encoding: "utf-8", // 设置编码
    uploadDir: uploadDir, // 设置上传目录
    keepExtensions: true, // 保留后缀
    maxFileSize: 100 * 1024 * 1024, // 最大文件大小 （默认20M => 2 * 1024 * 1024 ）
    minFileSize: 0, //最小文件大小
    maxTotalFileSize: 100 * 1024 * 1024,
    // maxFiles: 100, //最大文件数
    allowEmptyFiles: false,
    multiples: false
  });
  try {
    let [fields, file] = await form.parse(req);
    const params = {
      name: (fields.name || [])[0]
    };
    file = (file.file || [])[0];

    // console.warn("[解析表单结束]", fields, file);
    let filePath = file.filepath;
    let unZipPath = filePath + "-uncompress";
    await compressing.zip.uncompress(filePath, unZipPath);
    fs.rmSync(file.filepath); //删除缓存文件

    let appCachePath = filePath + "-app-cache";
    let appPathOfSdk = path.join(unZipPath, "public");
    if (fs.existsSync(appPathOfSdk)) {
      //sdk上传
      fs.existsSync(appPathOfSdk) && fs.renameSync(appPathOfSdk, appCachePath); //将插件缓存的文件移动到相应目录
      fs.existsSync(unZipPath) && fs.rmdirSync(unZipPath, { recursive: true }); //删除解压目录
    } else {
      fs.existsSync(unZipPath) && fs.renameSync(unZipPath, appCachePath); //将插件缓存的文件移动到相应目录
    }

    var appConfigPath = path.join(appCachePath, "ax-app/app.config.js");
    if (!fs.existsSync(appConfigPath)) {
      return res.json({ code: -1, message: "没有应用配置文件:" + appConfigPath });
    }
    let appConfig = fs.readFileSync(appConfigPath).toString();
    let app = resolveAppOfString(appConfig);
    // console.log("[上传应用][解析]", app, appConfig);
    if (!app || !app.id) {
      return res.json({ code: -1, message: "应用配置文件内容不合法:" + appConfigPath, app });
    }
    app.componentName = params.name || app.componentName + `_upload_${Date.now()}`;
    let t = new Date();
    let dbData = {
      name: app.componentName,
      updateTime: t.toLocaleString(),
      updateUserName: "测试用户(更新)",
      previewImg: "app-preview.png?t=" + t.getTime() //更新预览图更新标识
    };
    nedb.insert(dbData).then(async (result) => {
      if (!result.data || !result.data._id) {
        fs.rmdirSync(appCachePath, { recursive: true }); //删除缓存目录
        return res.json(result);
      }

      let dirOld = appCachePath;
      let dir = path.resolve(rootPath, result.data._id); //根据新应用id生成新应用目录
      try {
        !fs.existsSync(dir) && (await fs.mkdirSync(dir, { recursive: true })); // 判断文件夹是否存在,没用递归创建文件夹
        //复制应用资源文件
        fs.existsSync(path.join(dirOld, "ax/assets")) && (await fs.cpSync(path.join(dirOld, "ax/assets"), path.join(dir, "ax/assets"), { recursive: true }));

        //复制应用配置文件
        fs.existsSync(path.join(dirOld, "ax-app")) && (await fs.cpSync(path.join(dirOld, "ax-app"), path.join(dir, "ax-app"), { recursive: true }));

        //删除缓存目录(上传的资源缓存)
        fs.existsSync(dirOld) && fs.rmdirSync(dirOld, { recursive: true });
        changePermission(path.join(dir)); //修改目录权限(上传的资源缓存)
      } catch (error) {
        console.error("应用上传解析失败", error);
        return res.json({ code: -1, message: "应用上传解析失败", error });
      }

      //应用配置文件替换新的应用id
      let oldId = app.id;
      app.id = result.data._id;
      let appConfigStr = JSON.stringify(app);
      oldId && oldId.length > 10 && (appConfigStr = appConfigStr.replace(new RegExp(oldId, "g"), app.id)); //替换原应用id相关的代码
      let appConfigCode = appStr2configCode(appConfigStr);
      try {
        fs.writeFileSync(path.join(dir, "./ax-app/app.config.js"), Buffer.from(appConfigCode)); //保存应用配置
      } catch (error) {
        console.error("替换应用配置异常", error);
        return res.json({ code: -1, message: "替换应用配置异常", error });
      }

      res.json({ code: 200, message: "应用上传成功", data: app });
    });

    // console.log("[文件上传成功]", filesPath);
  } catch (error) {
    console.error("[应用上传异常]", error);
    res.json({ code: -1, message: "应用上传异常", error: error.message });
  }
});

//应用复制
router.post("/copy", function (req, res, next) {
  var params = req.body;

  var appConfigPath = path.join(rootPath, params.id, "ax-app/app.config.js");
  if (!fs.existsSync(appConfigPath)) {
    return res.json({ code: -1, message: "没有应用配置文件:" + appConfigPath });
  }
  let appConfig = fs.readFileSync(appConfigPath).toString();
  let app = resolveAppOfString(appConfig);
  // console.log("[下载应用][sdk]", app, appConfig);
  if (!app || !app.id) {
    return res.json({ code: -1, message: "应用配置不合法:" + appConfigPath, app });
  }

  delete app.id;
  app.componentName = params.name || app.componentName + `_copy_${Date.now()}`;

  let t = new Date();
  let dbData = {
    name: app.componentName,
    updateTime: t.toLocaleString(),
    updateUserName: "测试用户(更新)",
    previewImg: "app-preview.png?t=" + t.getTime() //更新预览图更新标识
  };

  nedb.insert(dbData).then(async (result) => {
    if (!result.data || !result.data._id) {
      return res.json(result);
    }

    let oldId = params.id;
    app.id = result.data._id;
    let appConfigStr = JSON.stringify(app);
    oldId && oldId.length > 10 && (appConfigStr = appConfigStr.replace(new RegExp(oldId, "g"), app.id)); //替换原应用id相关的代码
    let appConfigCode = appStr2configCode(appConfigStr);

    let dirOld = path.join(rootPath, params.id);
    let dir = path.join(rootPath, app.id);
    !fs.existsSync(dir) && fs.mkdirSync(dir, { recursive: true }); // 判断文件夹是否存在,没用递归创建文件夹
    await fs.cpSync(dirOld, dir, { recursive: true }); //复制文件或目录
    let cachePath = path.join(rootPath, app.id, ".cache"); //原应用缓存资源目录
    fs.statSync(cachePath).isDirectory() ? fs.rmdirSync(cachePath, { recursive: true }) : fs.rmSync(cachePath); //资源存在才需要删除; //目标目录存在,删除目标目录
    fs.writeFileSync(path.join(dir, "./ax-app/app.config.js"), Buffer.from(appConfigCode)); //保存应用配置

    // console.log("应用复制结束");
    res.json(result);
  });
});

//删除单条数据
router.post("/remove", function (req, res, next) {
  var params = req.body;
  if (!params.id) {
    return res.json({ code: -1, message: "没有需要删除的id" });
  }
  nedb.remove({ _id: params.id }).then((result) => {
    console.log("[删除应用目录]", result);
    if (!result.data) {
      return res.json(result);
    }
    try {
      let dir = path.join(rootPath, params.id);
      fs.existsSync(dir) && fs.rmdirSync(dir, { recursive: true }); //删除应用对应目录
    } catch (error) {
      console.error("[删除应用目录异常]", error);
      return res.json({ code: -1, message: "删除应用目录异常", error });
    }
    res.json(result);
  });
});

//查询列表数据
router.get("/getList", function (req, res, next) {
  var query = req.query || {};
  // current=1&size=14&name=&descs=update_time
  let limit = (query.size || 100) - 0;
  let skip = (query.current || 1) - 1;
  var params = {
    filter: {},
    skip: skip * limit, //分页
    limit: limit, //分页
    sort: { updateTime: -1 }
  };
  if (query.name) {
    params.filter.name = query.name; //过滤
  }
  if (query.descs) {
    params.sort[query.descs] = -1; //排序
  }
  nedb.find(params).then((result) => {
    (((result || {}).data || {}).records || []).map((item) => {
      item.id = item._id;
      delete item._id;
      return item;
    });
    res.json(result);
  });
});

//查询单条数据
router.get("/get", function (req, res, next) {
  var params = req.query;
  nedb.findOne(params).then((result) => {
    delete (result.data || {})._id;
    res.json(result);
  });
});

//保存数据
router.post("/save", function (req, res, next) {
  var params = req.body;
  if (!params) {
    return res.json({ code: -1, message: "没有需要保存的数据" });
  }
  let t = new Date();
  let dbData = {
    id: params.id,
    name: params.componentName,
    updateTime: t.toLocaleString(),
    updateUserName: "测试用户(更新)",
    previewImg: "app-preview.png?t=" + t.getTime() //更新预览图更新标识
  };

  if (!dbData.id) {
    delete dbData.id;
    dbData.createTime = dbData.updateTime;
    dbData.createUserName = dbData.updateUserName;
  }

  nedb[dbData && dbData.id ? "update" : "insert"](dbData).then(async (result) => {
    if (!result.data || !result.data._id) {
      return res.json(result);
    }
    console.log("应用保存结果", result);
    try {
      let appConfig = { ...params, ...result.data }; //合并入库数据
      let pathArr = [rootPath, appConfig._id, "ax-app"].filter((i) => i);
      let dir = path.join(...pathArr);
      !fs.existsSync(dir) && fs.mkdirSync(dir, { recursive: true }); // 判断文件夹是否存在,没用递归创建文件夹

      let appConfigStr = JSON.stringify(appConfig);
      let appConfigCode = appStr2configCode(appConfigStr);

      //保存历史记录
      let dirHistory = path.join(dir, "../.cache/history");
      !fs.existsSync(dirHistory) && fs.mkdirSync(dirHistory, { recursive: true }); // 判断文件夹是否存在,没用递归创建文件夹

      let targetPath = path.join(dirHistory, dateFormat(t.getTime(), "YYYYMMDD-HHmmss-S-") + "app.config.js");
      fs.writeFileSync(targetPath, Buffer.from(appConfigCode)); //保存应用配置历史记录
      // await fs.renameSync(filePath, targetPath);
      // if (req.query.cache != null) {  }

      //保存应用配置
      let filePath = path.join(dir, "app.config.js");
      fs.writeFileSync(filePath, Buffer.from(appConfigCode));

      //保存应用预览图片
      if (params.previewImg) {
        let previewImg = params.previewImg || ""; //预览图
        let base64 = previewImg.replace(/^data:image\/\w+;base64,/, ""); //去掉图⽚base64码前⾯部分data:image
        let dataBuffer = Buffer.from(base64, "base64");
        fs.writeFileSync(path.join(dir, "app-preview.png"), dataBuffer); //保存应用预览图片
      }
      console.log("保存应用文件结束");
    } catch (error) {
      console.error("[保存预览图片异常]", error);
    }
    res.json(result);
  });
});

export default router;
